package com.silknet.images;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.imageio.ImageIO;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.silknet.db.DBConnection;

public class ImageStore {
	private static TreeMap<String, ImageData> imageDataList = null;
	private static AtomicBoolean downloadedfromDB = new AtomicBoolean(false);
	public static String ICONS_DIR = "images/icons";
	public static String GENERATED_DIR = ICONS_DIR + "/generated";
	public static String EXT = "png";

	public static void copyFile(File src, File dst) throws IOException {
		InputStream in = null;
		OutputStream out = null;
		try {
			in = new FileInputStream(src);
			out = new FileOutputStream(dst);

			// Transfer bytes from in to out
			byte[] buf = new byte[1024];
			int len;
			while ((len = in.read(buf)) > 0) {
				out.write(buf, 0, len);
			}
		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			try {
				in.close();
			} catch (Exception e2) {
				// TODO: handle exception
			}
			try {
				out.close();
			} catch (Exception e2) {
				// TODO: handle exception
			}

		}
	}

	public static void addImageData(int id, String name,
			HttpServletRequest request, ServletContext context) {

		try {
			String basePath = request.getServletPath();
			String realpath = context.getRealPath(basePath);
			File jspPath = new File(realpath);
			if (!(jspPath.exists() && jspPath.isFile())) {
				return;
			}
			File directory = jspPath.getParentFile();
			File generatedDir = new File(directory, GENERATED_DIR);
			File iconsDir = new File(directory, ICONS_DIR);

			if (!downloadedfromDB.get()) {
				if (!generatedDir.exists()) {
					generatedDir.mkdirs();
				}
				File[] files = generatedDir.listFiles();
				for (int i = 0; i < files.length; i++) {
					files[i].delete();
				}
				downloadedfromDB.set(true);
			}
			File realFile = new File(iconsDir, name);
			if (!realFile.exists())
				return;

			String newFileName = id + "." + EXT;
			File generatedFile = new File(generatedDir, newFileName);
			copyFile(realFile, generatedFile);
			BufferedImage origImage = ImageIO.read(generatedFile);

			createNewImage(generatedDir, newFileName, origImage, 1, "d");
			createNewImage(generatedDir, newFileName, origImage, 2, "t");
		} catch (Exception e) {
			System.out.println("eeeeeeeee " + name);
			e.printStackTrace();
		}
	}

	private static void checkForNull() {
		if (imageDataList == null) {

			try {
				ArrayList<ImageData> list = getImages();
				imageDataList = new TreeMap<String, ImageData>();
				for (ImageData imageData : list) {
					imageDataList.put(imageData.getId() + "", imageData);
				}
			} catch (Exception e) {
			}
		}
	}

	public static ArrayList<ImageData> getImages() throws Exception {
		ArrayList<ImageData> result = new ArrayList<ImageData>();
		String sql = "select id,imgdata,imgname,contenttype  from tblimages order by 1";
		Connection con = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			con = DBConnection.getConnection("");
			stmt = con.prepareStatement(sql);

			rs = stmt.executeQuery();
			while (rs.next()) {
				ImageData r = new ImageData();
				r.setId(rs.getInt("id"));
				r.setImgData(rs.getBytes("imgData"));
				r.setImageName(rs.getString("imgname"));
				r.setContenttype(rs.getString("contenttype"));

				result.add(r);
			}
		} catch (Exception e) {
			throw new Exception(e.getMessage());
		} finally {
			try {
				rs.close();
			} catch (Exception e2) {

			}
			try {
				stmt.close();
			} catch (Exception e2) {

			}
			try {
				con.close();
			} catch (Exception e2) {

			}
		}

		return result;
	}

	private static void checkForNullDirectory(HttpServletRequest request,
			ServletContext context) {
		checkForNull();
		if (downloadedfromDB.get()) {
			return;
		}
		try {
			String basePath = request.getServletPath();
			String realpath = context.getRealPath(basePath);
			File jspPath = new File(realpath);
			if (!(jspPath.exists() && jspPath.isFile())) {
				return;
			}
			File directory = jspPath.getParentFile();
			File imagesDir = new File(directory, GENERATED_DIR);
			if (!imagesDir.exists()) {
				imagesDir.mkdir();
			}
			File[] files = imagesDir.listFiles();
			for (int i = 0; i < files.length; i++) {
				files[i].delete();
			}
			Set<String> keys = imageDataList.keySet();
			ArrayList<ImageData> toAdd = new ArrayList<ImageData>();

			for (String key : keys) {
				ImageData imageData = imageDataList.get(key);
				saveFile(imagesDir, imageData);
				String fileName = getFileNameFor(imageData);
				BufferedImage origImage = ImageIO.read(new File(imagesDir,
						fileName));
				int lastindex = imageData.getImageName().lastIndexOf(".");
				String ext = imageData.getImageName().substring(lastindex + 1);
				createNewImage(toAdd, imagesDir, imageData, origImage, 1, "d",
						ext);
				createNewImage(toAdd, imagesDir, imageData, origImage, 2, "t",
						ext);
			}
			for (ImageData imageData : toAdd) {
				imageDataList.put(imageData.getPrefix() + imageData.getId(),
						imageData);
			}
			downloadedfromDB.set(true);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static void createNewImage(ArrayList<ImageData> toAdd,
			File imagesDir, ImageData imageData, BufferedImage origImage,
			int count, String name, String ext) throws IOException {
		int w = origImage.getWidth();
		int h = origImage.getHeight();
		int addW = (w / 10);
		int addH = (h / 10);
		BufferedImage newImage = new BufferedImage(w + (addW * count), h
				+ (addH * count), BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = newImage.createGraphics();
		int cwAdd = addW * count;
		int chAdd = 0;
		for (int i = 0; i < count + 1; i++) {
			g.drawImage(origImage, cwAdd, chAdd, w, h, null);
			cwAdd -= addW;
			chAdd += addH;
		}
		g.dispose();
		ByteArrayOutputStream bios = new ByteArrayOutputStream();
		ImageIO.write(newImage, ext, bios);
		byte[] ret = bios.toByteArray();
		bios.close();
		if (imageData != null) {
			ImageData newImageData = new ImageData();
			newImageData.setId(imageData.getId());
			newImageData.setContenttype(imageData.getContenttype());
			newImageData.setPrefix(name);
			newImageData.setImageName(imageData.getImageName());
			newImageData.setImgData(ret);
			saveFile(imagesDir, newImageData);
			if (toAdd != null)
				toAdd.add(newImageData);
		}

	}

	private static void createNewImage(File generatedDir, String newFileName,
			BufferedImage origImage, int count, String addon)
			throws IOException {
		int w = origImage.getWidth();
		int h = origImage.getHeight();
		int addW = (w / 10);
		int addH = (h / 10);
		BufferedImage newImage = new BufferedImage(w + (addW * count), h
				+ (addH * count), BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = newImage.createGraphics();
		int cwAdd = addW * count;
		int chAdd = 0;
		for (int i = 0; i < count + 1; i++) {
			g.drawImage(origImage, cwAdd, chAdd, w, h, null);
			cwAdd -= addW;
			chAdd += addH;
		}
		g.dispose();
		ByteArrayOutputStream bios = new ByteArrayOutputStream();
		ImageIO.write(newImage, EXT, bios);
		byte[] ret = bios.toByteArray();
		bios.close();

		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(new File(generatedDir, addon
					+ newFileName));
			fos.write(ret);
			fos.flush();
		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			try {
				if (fos != null) {
					fos.close();
				}
			} catch (Exception e2) {
				// TODO: handle exception
			}
		}

	}

	private static String getFileNameFor(ImageData imageData) {
		if (imageData == null) {
			return "";
		}
		return imageData.getPrefix() + imageData.getId() + "_"
				+ imageData.getImageName();
	}

	public static ImageData getImageData(String id) {
		checkForNull();
		return imageDataList.get(id);
	}

	public static String getImageURL(HttpServletRequest request,
			ServletContext context, String id) {
		// imageDataList=null;
		// downloadedfromDB=false;
		if (id == null) {
			return null;
		}
		checkForNullDirectory(request, context);
		String redirect = GENERATED_DIR + "/"
				+ getFileNameFor(getImageData(id));
		return redirect;
	}

	private static void saveFile(File imageDir, ImageData imageData) {
		String imageName = getFileNameFor(imageData);
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(new File(imageDir, imageName));
			fos.write(imageData.getImgData());
			fos.flush();
		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			try {
				if (fos != null) {
					fos.close();
				}
			} catch (Exception e2) {
				// TODO: handle exception
			}
		}
	}

	public void addImage(ImageData imageData) {
		checkForNull();
		imageDataList.put(imageData.getId() + "", imageData);
	}

	public void removeImage(int id) {
		imageDataList.remove(id);
	}
}
